<?php
/**
 * Created by PhpStorm.
 * User: Keter
 * Date: 2016/8/8
 * Time: 13:44
 */
class WeixinLogin extends RegisterBase
{
    public $validateToken = false;

    /**
     * 逻辑处理
     */
    public function logic()
    {
        $tokenInfo = $this->getAccessToken();
        $newUser = array();

        //是否有存在的账号
        $uid = $this->checkExistsUser($tokenInfo['openID']);
        if ($uid > 0){
            $newUser = $this->getUser($uid);
            if ($newUser) {
                $this->refreshAccessToken($uid, $tokenInfo);
            }
        }

        //如果没有已存在的账号，则创建
        if (empty($newUser)) {
            $userInfo = $this->createUser($tokenInfo);
            $this->afterRegister($userInfo);
            $this->saveTokenInfo($userInfo['uid'], $tokenInfo);
            $newUser = $this->getExtraInfo($userInfo);
            $newUser = $this->afterUserInfo($newUser);
        }

        //登录失败
        if ($newUser) {
            //刷新个人微信信息
            $weixinInfo = $this->updateUser($newUser['uid'], $tokenInfo);
            //传code的时候，要返回autoToken
            if (isset($this->params['code'])) {
                $newUser['autoToken'] = $this->getAutoToken($tokenInfo['openID']);
            }
            //登录成功
            $newUser = array_merge($newUser, $weixinInfo);
            $newUser = $this->formatNumber($newUser);
            $this->afterLogin($newUser);
            $this->returnData('suc_weixin_login', $newUser);
        } else {
            $this->returnError('failed_login');
        }
    }

    /**
     * 刷新微信Token有效期
     * @param $uid
     * @param $tokenInfo
     * @return array|bool|mixed|string
     */
    public function refreshAccessToken($uid, $tokenInfo)
    {
        //暂时前面getAccessToken()每次都会更新，所以这里不会刷新
        $diffTime = time() - (integer)$tokenInfo['createTime'];

        //提前半小时刷新
        if ($diffTime < $tokenInfo['expiresIn'] - 60*30) {
            //return true;
        }

        $uri = sprintf(
            GlobalConfig::$weixin_config['refresh_uri'],
            GlobalConfig::$weixin_config['app_id'],
            $tokenInfo['refreshToken']
        );

        $content = $this->getTokenInfo($uri);
        if ($content) {
            $this->saveTokenInfo($uid, $content);
            return $content;
        }

        $this->i($uri);
        //授权信息已失效
        $this->returnError('failed_grant_update', -2);
    }

    /**
     * 创建用户
     * @param $tokenInfo
     * @return array
     */
    public function createUser($tokenInfo)
    {
        $userInfo = $this->getUserInfo();

        //开始事务
        $this->userRedis->multi();
        $result = $this->createNewUser($userInfo);

        if ($result) {
            //生成UID和openID的匹配信息
            $arr = array("uid" => $userInfo['uid']);
            $result = $this->userRedis->hMset("W:" . $tokenInfo['openID'], $arr);
        }

        if ($result){
            //提交事务
            $this->userRedis->exec();
            return $userInfo;
        } else {
            //撤消事务
            $this->userRedis->discard();
            $this->returnError("failed_redis_act");
        }
    }

    /**
     * 获取Token
     * @return array|bool|mixed|string
     */
    public function getAccessToken()
    {
        if (isset($this->params['code'])) {
            $uri = sprintf(
                GlobalConfig::$weixin_config['access_token_uri'],
                GlobalConfig::$weixin_config['app_id'],
                GlobalConfig::$weixin_config['app_secret'],
                $this->params['code']
            );
            $tokenInfo = $this->getTokenInfo($uri);
            if (empty($tokenInfo)) {
                $this->i('params', $this->params);
                $this->i('uri', $uri);
                $this->returnError('failed_grand_get');
            }
        } else {
            $tokenInfo = array();
            if (isset($this->params['autoToken']) && $this->params['autoToken']) {
                $autoToken = $this->params['autoToken'];
                if ($this->userRedis->exists('WLM:' . $autoToken)) {
                    $tokenInfo = $this->userRedis->hMget(
                        'WLM:' . $autoToken,
                        ['accessToken', 'expiresIn', 'refreshToken', 'openID', 'scope', 'code', 'createTime']
                    );
                }
            }
            if (empty($tokenInfo)) {
                $this->i('params', $this->params);
                $this->returnError('invalid_request');
            }
        }

        return $tokenInfo;
    }

    /**
     * 刷新个人微信信息（更新昵称和头像）
     * @param $uid
     * @param $tokenInfo
     */
    public function updateUser($uid, $tokenInfo)
    {
        //更新微信个人信息
        $weixinInfo = $this->getWeixinInfo($tokenInfo);
        $this->i('get_weixin_info', $weixinInfo);

        $result = $this->userRedis->hMset('WI:' . $uid, $weixinInfo);
        if (!$result) {
            $this->logWarning("UID {$uid} weixin info update error.", $weixinInfo);
            return array();
        }

        //更新用户资料中的昵称和头像为微信的
        $arr = array(
            'nickname' => $weixinInfo['nickname'],
            'avatar' => $weixinInfo['avatar'],
            'address' => $weixinInfo['country']
                . _SPACE
                . $weixinInfo['province']
                . _SPACE
                . $weixinInfo['city'],
            'sex' => $this->sexMatch($weixinInfo['sex'])
        );

        $result = $this->userRedis->hMset("U:" . $uid, $arr);
        if (!$result) {
            $this->logWarning("UID {$uid} weixin info update error.", $arr);
        }

        return $arr;
    }

    /**
     * 性别匹配
     * @param $sex
     * @return int
     */
    public function sexMatch($sex)
    {
        $result = 2;

        if ($sex == 1) {
            $result = 1;
        } elseif ($sex == 2) {
            $result = 0;
        }

        return $result;
    }

    /**
     * 判断微信账号是否已注册
     * @param $openID
     * @return int
     */
    public function checkExistsUser($openID)
    {
        $uid = 0;
        $key = "W:" . $openID;

        if ($this->userRedis->exists($key)) {
            $userToImei = $this->userRedis->hMget($key, array("uid"));
            $uid = $userToImei["uid"];
        }

        return $uid;
    }

    /**
     * 获取用户微信个人信息
     * @param $tokenInfo
     * @return mixed
     */
    public function getWeixinInfo($tokenInfo)
    {
        $uri = sprintf(
            GlobalConfig::$weixin_config['user_info_uri'],
            $tokenInfo['accessToken'],
            $tokenInfo['openID']
        );

        $content = GetContents::remote($uri);
        if ($content) {
            $content = json_decode($content, true);
            if (!isset($content['errcode'])) {
                $content = array(
                    'openID'     => $content['openid'],
                    'nickname'   => $content['nickname'],
                    'sex'        => $content['sex'],
                    'province'   => $content['province'],
                    'city'       => $content['city'],
                    'country'    => $content['country'],
                    'avatar'     => $content['headimgurl'],
                    'privilege'  => json_encode($content['privilege'], JSON_UNESCAPED_UNICODE),
                    'unionID'    => $content['unionid'], //用户统一标识
                    'createTime' => time(),
                );
                return $content;
            }
            $this->i(json_encode($content, JSON_UNESCAPED_UNICODE));
        }

        $this->i(json_encode($this->params, JSON_UNESCAPED_UNICODE));
        $this->i($uri);
        return array();
    }

    /**
     * 保存Token数据
     * @param $uid
     * @param $content
     */
    public function saveTokenInfo($uid, $content)
    {
        $openIDKey = $this->getAutoToken($content['openID']);
        $result = $this->userRedis->hMset('WLM:' . $openIDKey, $content);

        if (!$result) {
            $this->returnError("UID {$uid} token save error.");
        }

        $this->i('suc_save_token_info', $content);
    }

    /**
     * 获取自动登录的token加密串
     * @param $openID
     * @return string
     */
    public static function getAutoToken($openID)
    {
        return md5($openID . GameConfig::$weixin_login_key);
    }

    /**
     * 获取TOKEN及刷新数据
     * @param $uri
     * @return array|bool|mixed|string
     */
    public function getTokenInfo($uri)
    {
        $content = GetContents::remote($uri);

        if ($content) {
            $content = json_decode($content, true);
            if (isset($content['errcode'])) {
                $this->i(json_encode($content, JSON_UNESCAPED_UNICODE));
            } else {
                $content = array(
                    'accessToken'  => $content['access_token'],
                    'expiresIn'    => $content['expires_in'],
                    'refreshToken' => $content['refresh_token'],
                    'openID'       => $content['openid'],
                    'scope'        => $content['scope'],
                    'code'         => $this->params['code'],
                    'createTime'   => time(),
                );
                return $content;
            }
        }

        return array();
    }
}